<template>
    <div class="engine">
        <div class="engine-hd" key="engine-hd">
            <div>
                <el-switch
                    v-model="request.jumpOverETL"
                    active-text="执行ETL"
                    :active-value="false"
                    inactive-text="跳过ETL"
                    :inactive-value="true"
                    style="margin-right:10px"
                    size="mini"
                    :disabled="processData.calculateEngineStateType !== 'UNINITIALIZED'"
                />
                <el-select
                    v-model="request.articulation"
                    size="mini"
                    style="width: 160px; padding-right: 10px;"
                    :disabled="processData.calculateEngineStateType !== 'UNINITIALIZED'"
                >
                    <el-option value="1" label="不执行勾稽关系" />
                    <el-option value="2" label="执行条目相关勾稽关系" />
                    <el-option value="3" label="执行所有勾稽关系" />
                    <el-option value="NOT_IMPORT_DATA" label="不执行导数" />
                </el-select>
                <el-button
                    type="primary"
                    @click="initEngine"
                    size="mini"
                    v-loading="loading"
                    :disabled="processData.calculateEngineStateType !== 'UNINITIALIZED'"
                >
                    {{ processData.calculateEngineStateType == 'INITIALIZED' ? '定时初始化' : '初始化' }}
                </el-button>
                <el-button
                    type="danger"
                    @click="closeEngine"
                    v-loading="closeButtonLoading"
                    size="mini"
                    :disabled="processData.calculateEngineStateType === 'UNINITIALIZED' && !judgeExistError(processData)"
                >
                    关闭
                </el-button>
                <el-button type="primary" @click="handleAgainConnect" size="mini" v-show="showAgainConnect">重新连接</el-button>
            </div>
            <div style="margin-top: 5px;">
                <el-radio-group v-model="processData.calculateEngineStateType" disabled>
                    <el-radio label="UNINITIALIZED">未初始化</el-radio>
                    <el-radio label="INIT_DATA">初始化数据中</el-radio>
                    <el-radio label="INIT_ENTRY">条目初始化</el-radio>
                    <el-radio label="INITIALIZED">初始化完成</el-radio>
                </el-radio-group>
                <span style="color: red; float:right;">{{ judgeExistError(processData) }}</span>
            </div>
        </div>
        <div class="engine-time" v-if="judgeExistError(processData) || processData.calculateEngineStateType !== 'UNINITIALIZED'" key="engine-time">
            <RiskControlEngineTime :calculateEngineStateType="processData.calculateEngineStateType" :processData="processData" />
        </div>
        <div
            class="engine-diagram"
            v-show="judgeExistError(processData) || processData.calculateEngineStateType !== 'UNINITIALIZED'"
            v-loading="G6Loading"
            key="engine-diagram"
        >
            <div class="engine-diagram-icon">
                <div class="engine-diagram-icon-wrap">
                    <span v-for="icon in engineIcon" :key="icon.text">
                        <img :src="icon.img" />
                        <span>{{ icon.text }}</span>
                    </span>
                </div>
            </div>
            <div class="engine-diagram-box" ref="box"></div>
        </div>
        <div
            class="engine-result"
            v-loading="footLoading"
            v-if="['INIT_ENTRY', 'INITIALIZED'].includes(this.processData.calculateEngineStateType)"
            key="engine-result"
        >
            <div class="engine-result-hd">
                <span>初始化结果：</span>
                <el-select size="mini" v-model="footData.type" @change="initFootData($event, processData)" style="width: 150px">
                    <el-option value="entryInit" label="条目初始化" />
                    <el-option value="entrySync" label="条目同步" />
                    <el-option value="dynamicSync" label="动态维度同步" />
                </el-select>
                <span style="margin-left: 20px">{{ footData.type == 'dynamicSync' ? '查找维度：' : '查找条目：' }}</span>
                <el-input size="mini" v-model="footData.search" placeholder="编号/名称" style="width: 150px" clearable />
                <el-button type="primary" @click="searchByCodeOrName" style="margin-left:10px">查询</el-button>
            </div>
            <div class="engine-result-body">
                <p style="color: red">【成功数量】：{{ footData.type == 'entryInit' ? successInitEntryCodes.length : amount.successAmount }}</p>
                <!-- <p>{{ filterSuccessInitEntryCodes.join(', ') }}</p> -->
                <p style="color: red">【失败数量】：{{ footData.type == 'entryInit' ? errorInitEntryCodes.length : amount.errorAmount }}</p>
                <!-- <p>{{ filterErrorInitEntryCodes.join(', ') }}</p> -->
                <!-- <div v-show="footData.type === 'entryInit'" > -->
                <p style="color: red" v-show="footData.type === 'entryInit'">【过滤数量】：{{ filterInitEntryCodes.length }}</p>
                <!-- <p>{{ filterFilterInitEntryCodes.join(', ') }}</p> -->
                <!-- </div> -->
            </div>
            <div class="engine-result-content">
                <div class="border">
                    <h3>{{ footData.type == 'dynamicSync' ? '成功维度:' : '成功条目:' }}</h3>
                    <RiskTable
                        :msg="successMsg"
                        @handleFilter="handleFilterChange($event, 'success')"
                        style="height:calc(100% - 70px)"
                        :key="'table1' + tableKey"
                    ></RiskTable>
                    <!-- :pages="pagingSuccess"  @getList="getList($event, 'success')" -->
                    <RiskPagination :paging="pagingSuccess" @page-change="pageChange(successFilterList, 'success')"></RiskPagination>
                </div>
                <div class="border">
                    <h3>{{ footData.type == 'dynamicSync' ? '失败维度:' : '失败条目:' }}</h3>
                    <RiskTable
                        :msg="errorMsg"
                        @handleFilter="handleFilterChange($event, 'error')"
                        style="height:calc(100% - 70px)"
                        :key="'table2' + tableKey"
                    ></RiskTable>
                    <!--  :pages="pagingError"    @getList="getList($event, 'error')" -->
                    <RiskPagination :paging="pagingError" @page-change="pageChange(errorFilterList, 'error')"></RiskPagination>
                </div>
            </div>
        </div>
    </div>
</template>

<script lang="ts">
import { Component, Vue, Watch } from 'vue-property-decorator';
import RiskControlEngineTime from './risk-control-engine/risk-control-engine-time.vue';

import G6 from '@antv/g6';
import { getUser } from '@/utils/user-util';
import { getConfigItem, getCurrentPageData, GunDataGzip, StringToBase64, UUID12 } from '@/utils/tools';
import { engineState, getLatestSyncEntryData, initEngine, engineStop, getSyncDataList, getSyncDataDetailItem } from '@/pages/system-maintence/api';
import RiskTable from '@/common/components/risk-table.vue';
import RiskPagination from '@/common/components/risk-pagination.vue';

let Util = G6.Util;
// 图片动画
G6.registerNode(
    'inner-animate',
    {
        afterDraw(cfg, group) {
            const size = cfg.size;
            const width = size[0] - 3;
            const height = size[1] - 3;
            const image = group.addShape('image', {
                attrs: {
                    x: -width / 2,
                    y: -height / 2,
                    width,
                    height,
                    img: cfg.img,
                },
                name: 'image-shape',
            });
            image.animate(
                ratio => {
                    const matrix = Util.mat3.create();
                    const toMatrix = Util.transform(matrix, [['r', ratio * Math.PI * 2]]);
                    return {
                        matrix: toMatrix,
                    };
                },
                {
                    repeat: true,
                    duration: 3000,
                    easing: 'easeLinear',
                }
            );
        },
    },
    'circle'
);

G6.registerEdge(
    'line-dash-straight',
    {
        afterDraw(cfg, group) {
            // get the first shape in the group, it is the edge's path here=
            const shape = group.get('children')[0];
            let index = 0;
            // Define the animation
            shape.animate(
                () => {
                    index++;
                    if (index > 9) {
                        index = 0;
                    }
                    const res = {
                        lineDash: [4, 4, 4, 4],
                        lineDashOffset: -index,
                    };
                    // returns the modified configurations here, lineDash and lineDashOffset here
                    return res;
                },
                {
                    repeat: true, // whether executes the animation repeatly
                    duration: 3000, // the duration for executing once
                }
            );
        },
    },
    'circle'
);

// 正常未初始化时的图标
const INFO_NODE = {
    style: {
        fill: 'rgb(222,222,222)',
        stroke: 'gray',
    },
};
const INFO_NODE_IMG =
    '';

// 正在初始化时的图标
const SYNC_NODE = {
    size: [25, 25],
    type: 'inner-animate',
    img:
        '',
    style: {
        fill: 'rgb(255,255,255)',
        stroke: 'rgb(255,255,255)',
    },
};

// 初始化成功的图标
const SUCCESS_NODE = {};
const SUCCESS_NODE_IMG =
    '';

// 初始化失败的图标
const ERROR_NODE = {
    size: [25, 25],
    type: 'image',
    img:
        '',
    style: {
        fill: 'rgb(255,255,255)',
        stroke: 'rgb(255,255,255)',
    },
};

// 跳过时的图标
const SKIP_NODE = {
    size: [25, 25],
    type: 'image',
    img:
        '',
    style: {
        fill: 'rgb(255,255,255)',
        stroke: 'rgb(255,255,255)',
    },
};

const INFO_EDGE = {
    style: {
        stroke: 'rgb(150,150,150)',
    },
};

const SYNC_EDGE = {
    style: {
        stroke: '#1890ff',
    },
    type: 'line-dash-straight',
};
const SUCCESS_EDGE = {
    style: {
        stroke: '#1890ff',
    },
};
const ERROR_EDGE = {
    style: {
        stroke: 'red',
    },
};

@Component({ name: 'RiskControlEngine', components: { RiskControlEngineTime, RiskTable, RiskPagination } })
export default class RiskControlEngine extends Vue {
    BASE_URL_WS = getConfigItem('BASE_URL_WS');

    mounted() {
        this.renderG6 = new G6.Graph({
            container: this.$refs.box as HTMLElement,
            // 画布宽高
            width: 1400,
            height: 270,
        });
        this.searchDataEngineStatus();
        this.initWebsocketConnect();
    }

    beforeDestroy() {
        if (this.TimeInterval) {
            clearTimeout(this.TimeInterval);
            this.TimeInterval = null;
        }
        if (this.TimeSendMessage) {
            clearInterval(this.TimeSendMessage);
            this.TimeSendMessage = null;
        }

        try {
            this.webSocketInstance.close();
        } catch (e) {}
    }

    amount = {
        successAmount: 0,
        errorAmount: 0,
    };

    columns = [
        { name: '编号', val: 'code', filters: [{ data: '' }], search: true },
        { name: '名称', val: 'name', filters: [{ data: '' }], search: true },
    ];

    successMsg: any = {
        returnData: {},
        dataKey: 'list',
        title: this.columns,
        checked: { on: false, option: false },
        hidePage: true,
    };

    errorMsg: any = {
        returnData: {},
        dataKey: 'list',
        title: this.columns,
        checked: { on: false, option: false },
        hidePage: true,
    };

    pagingSuccess = {
        total: 0,
        currentPage: 1,
        pageSize: 10,
    };

    pagingError = {
        total: 0,
        currentPage: 1,
        pageSize: 10,
    };
    batchId: string = '';
    successItemsList: any[] = []; // 条目初始化成功条目(分页)
    errorItemsList: any[] = []; // 条目初始化失败条目(分页)
    tableKey: number = -1; // 表单Key

    private loading = false;

    private G6Loading = false;

    // 示例图标
    private engineIcon = [
        {
            img: INFO_NODE_IMG,
            text: '未开始',
        },
        {
            img: SKIP_NODE.img,
            text: '跳过',
        },
        {
            img: SYNC_NODE.img,
            text: '进行中',
        },
        {
            img: ERROR_NODE.img,
            text: '错误',
        },
        {
            img: SUCCESS_NODE_IMG,
            text: '完成',
        },
    ];

    private initButtonLoading = false;
    private closeButtonLoading = false;

    // 初始化进度参数
    private initStatus = {
        UNINITIALIZED: '未初始化',
        INIT_DATA: '初始化数据中',
        INIT_ENTRY: '条目初始化',
        INITIALIZED: '初始化完成',
    };
    // 初始化的进度多选框值
    private processData = {
        calculateEngineStateType: 'UNINITIALIZED',
    };
    private request = {
        initAll: true,
        articulation: '',
        initEntryCodes: [],
        messageCode: '',
        jumpOverETL: false,
        riskCalType: 'INSTRUCTION',
    };

    // 显示重新连接
    private showAgainConnect = false;

    private renderG6 = null;

    // websocket
    private webSocketInstance = null;
    private TimeInterval = null;
    private TimeSendMessage = null;
    private initButtonState = false;

    // 成功、失败、过滤的列表
    private footData = {
        type: 'entryInit',
        search: '',
    };
    private footLoading = false;
    private successInitEntryCodes = [];
    private errorInitEntryCodes = [];
    private filterInitEntryCodes = [];

    // get filterSuccessInitEntryCodes() {
    //     return this.successInitEntryCodes.filter(str => {
    //         return str.indexOf(this.footData.search.trim()) > -1;
    //     });
    // }
    // get filterErrorInitEntryCodes() {
    //     return this.errorInitEntryCodes.filter(str => {
    //         return str.indexOf(this.footData.search.trim()) > -1;
    //     });
    // }
    // get filterFilterInitEntryCodes() {
    //     return this.filterInitEntryCodes.filter(str => {
    //         return str.indexOf(this.footData.search.trim()) > -1;
    //     });
    // }

    initEngine() {
        this.loading = true;
        let request = JSON.parse(JSON.stringify(this.request));
        request.messageCode = UUID12() + '-' + new Date().getTime();
        request.initAll = true;
        request.riskCalType = 'INSTRUCTION';
        this.initButtonLoading = true;
        initEngine(request)
            .then(res => {})
            .catch(() => {
                this.loading = false;
            })
            .finally(() => {
                this.initButtonLoading = false;
                // this.searchDataEngineStatus();
            });
    }

    @Watch('showAgainConnect', { immediate: true, deep: true })
    watchShowAgainConnect(newData, oldData) {
        if (newData && newData !== oldData) {
            console.log('监听到WS已掉线, 自动发起心跳MSG');
            this.handleAgainConnect();
        }
    }

    /**
     * 重新连接WEB-SOCKET
     */
    handleAgainConnect() {
        if (this.TimeInterval) {
            clearTimeout(this.TimeInterval);
            this.TimeInterval = null;
        }
        if (this.TimeSendMessage) {
            clearInterval(this.TimeSendMessage);
            this.TimeSendMessage = null;
        }
        try {
            this.webSocketInstance.close();
        } catch (e) {}

        this.searchDataEngineStatus();
        this.initWebsocketConnect();
    }

    /**
     * 查询状态
     */
    searchDataEngineStatus() {
        engineState().then(res => {
            let state = res.state;
            let processData = JSON.parse(res.process || '{}');
            let request = {
                initAll: true,
                initEntryCodes: [],
                messageCode: '',
                jumpOverETL: true,
                articulation: '',
                riskCalType: 'INSTRUCTION',
            };
            if (res.request) {
                for (let requestKey in request) {
                    request[requestKey] = res.request[requestKey] === undefined ? request[requestKey] : res.request[requestKey];
                }
            }

            if (!processData) {
                processData = {};
            }
            if (state !== processData.calculateEngineStateType) {
                processData.calculateEngineStateType = state;
            }
            this.handleMessage(processData);
            this.processData = processData;
            this.request = request;
        });
    }
    /**
     * 初始化websocket连接
     */
    initWebsocketConnect() {
        let Authentication = getUser().sessionId;
        let webSocket = new WebSocket(this.BASE_URL_WS + '/dataEngine/socket/' + StringToBase64(Authentication));
        webSocket.onopen = e => {
            this.$notify.success({
                title: '连接成功',
                message: '风控引擎初始化消息服务连接成功',
            });
            this.showAgainConnect = false;
        };
        webSocket.onmessage = e => {
            if (this.TimeInterval) {
                clearTimeout(this.TimeInterval);
                this.TimeInterval = null;
                this.initButtonState = false;
            }
            let data = JSON.parse(GunDataGzip(e.data));
            console.log('风控引擎初始化 WEBSOCKET收到消息：', data);
            this.handleMessage(data);
            this.processData = data;
        };

        webSocket.onclose = e => {
            this.$notify.success({
                title: '风控引擎已断开',
                message: '风控引擎初始化消息服务已断开',
            });
            this.showAgainConnect = true;
        };

        this.webSocketInstance = webSocket;
        if (this.TimeSendMessage) {
            clearInterval(this.TimeSendMessage);
            this.TimeSendMessage = null;
        }
        // 每隔1个小时发送一次消息 确保在使用nginx的情况下不会有断连的情况，同时约定nginx后台配置超时时间超过一个小时
        this.TimeSendMessage = setInterval(() => {
            try {
                webSocket.send('引擎初始化-发送WEBSOCKET心跳消息');
            } catch (e) {}
        }, 1000 * 60 * 60);
    }

    /**
     * 处理消息
     */
    handleMessage(data) {
        this.loading = false;
        if (!data.instructionInitDataState) {
            this.G6Loading = true;
        } else {
            this.G6Loading = false;
        }
        // 处理底部的数据
        this.initFootData(this.footData.type, JSON.parse(JSON.stringify(data)));

        let orgData = JSON.parse(JSON.stringify(data));
        orgData = this.changeDataFormat(orgData);
        let x = 20;
        let nodes = [];
        let edges = [];
        let lastNodeId = 'start-after';
        nodes.push({
            id: 'start',
            x: x,
            y: 120,
            label: '开始',
            ...this.judgeNodeType(orgData, 'start', false),
            labelCfg: {
                position: 'bottom',
            },
        });
        x += 150;
        nodes.push({
            id: 'start-after',
            x: x,
            y: 120,
            ...this.judgeNodeType(orgData, 'start-after', false),
        });
        edges.push({
            source: 'start',
            target: 'start-after',
            style: {
                stroke: '#1890ff',
            },
            ...this.judgeEdgeType(orgData, 'start', 'start-after', false),
        });

        // etl之前
        let beforEtl = orgData.instructionInitDataState.beforeEtlInits;
        if (beforEtl.length !== 0) {
            x += 150;
        }
        if (beforEtl.length === 1) {
            nodes.push({
                id: 'before-1',
                x: x,
                y: 120,
                label: beforEtl[0],
                labelCfg: {
                    position: 'bottom',
                },
                ...this.judgeNodeType(orgData, 'before-1', true),
            });
            edges.push({
                source: lastNodeId,
                target: 'before-1',
                style: {
                    stroke: '#1890ff',
                },
                ...this.judgeEdgeType(orgData, lastNodeId, 'before-1', false),
            });
            edges.push({
                source: 'before-1',
                target: 'before-end',
                style: {
                    stroke: '#1890ff',
                },
                ...this.judgeEdgeType(orgData, 'before-1', 'before-end', true),
            });
        } else if (beforEtl.length > 1) {
            let interval = 200 / (beforEtl.length - 1);
            for (let i = 0; i < beforEtl.length; i++) {
                nodes.push({
                    id: 'before-' + (i + 1),
                    x: x,
                    y: 20 + i * interval,
                    label: beforEtl[i],
                    labelCfg: {
                        position: 'bottom',
                    },
                    ...this.judgeNodeType(orgData, 'before-' + (i + 1), true),
                });
                edges.push({
                    source: lastNodeId,
                    target: 'before-' + (i + 1),
                    style: {
                        stroke: '#1890ff',
                    },
                    ...this.judgeEdgeType(orgData, lastNodeId, 'before-' + (i + 1), false),
                });
                edges.push({
                    source: 'before-' + (i + 1),
                    target: 'before-end',
                    style: {
                        stroke: '#1890ff',
                    },
                    ...this.judgeEdgeType(orgData, 'before-' + (i + 1), 'before-end', true),
                });
            }
        }
        if (beforEtl.length !== 0) {
            x += 150;
            lastNodeId = 'before-end';
            nodes.push({
                id: 'before-end',
                x: x,
                y: 120,
                ...this.judgeNodeType(orgData, 'before-end', false),
            });
        }
        // etl之中
        let togetherEtl = orgData.instructionInitDataState.togetherEtlInits;
        if (togetherEtl.length !== 0) {
            x += 150;
        }
        if (togetherEtl.length === 1) {
            nodes.push({
                id: 'together-1',
                x: x,
                y: 120,
                label: togetherEtl[0],
                labelCfg: {
                    position: 'bottom',
                },
                ...this.judgeNodeType(orgData, 'together-1', true),
            });
            edges.push({
                source: lastNodeId,
                target: 'together-1',
                style: {
                    stroke: '#1890ff',
                },
                ...this.judgeEdgeType(orgData, lastNodeId, 'together-1', false),
            });
            edges.push({
                source: 'together-1',
                target: 'together-end',
                style: {
                    stroke: '#1890ff',
                },
                ...this.judgeEdgeType(orgData, 'together-1', 'together-end', true),
            });
        } else if (togetherEtl.length > 1) {
            let interval = 200 / (togetherEtl.length - 1);
            for (let i = 0; i < togetherEtl.length; i++) {
                nodes.push({
                    id: 'together-' + (i + 1),
                    x: x,
                    y: 20 + i * interval,
                    label: togetherEtl[i],
                    ...this.judgeNodeType(orgData, 'together-' + (i + 1), true),
                    labelCfg: {
                        position: 'bottom',
                    },
                });
                edges.push({
                    source: lastNodeId,
                    target: 'together-' + (i + 1),
                    style: {
                        stroke: '#1890ff',
                    },
                    ...this.judgeEdgeType(orgData, lastNodeId, 'together-' + (i + 1), false),
                });
                edges.push({
                    source: 'together-' + (i + 1),
                    target: 'together-end',
                    style: {
                        stroke: '#1890ff',
                    },
                    ...this.judgeEdgeType(orgData, 'together-' + (i + 1), 'together-end', true),
                });
            }
        }
        if (togetherEtl.length !== 0) {
            x += 150;
            lastNodeId = 'together-end';
            nodes.push({
                id: 'together-end',
                x: x,
                y: 120,
                ...this.judgeNodeType(orgData, 'together-end', false),
            });
        }
        // etl之后
        let afterEtl = orgData.instructionInitDataState.afterEtlInits;
        if (afterEtl.length !== 0) {
            x += 150;
        }
        if (afterEtl.length === 1) {
            nodes.push({
                id: 'after-1',
                x: x,
                y: 120,
                label: afterEtl[0],
                labelCfg: {
                    position: 'bottom',
                },
            });
            edges.push({
                source: lastNodeId,
                target: 'after-1',
                style: {
                    stroke: '#1890ff',
                },
                ...this.judgeEdgeType(orgData, lastNodeId, 'after-1', false),
            });
            edges.push({
                source: 'after-1',
                target: 'after-end',
                style: {
                    stroke: '#1890ff',
                },
                ...this.judgeEdgeType(orgData, 'after-1', 'after-end', true),
            });
        } else if (afterEtl.length > 1) {
            let interval = 200 / (afterEtl.length - 1);
            for (let i = 0; i < afterEtl.length; i++) {
                nodes.push({
                    id: 'after-' + (i + 1),
                    x: x,
                    y: 20 + i * interval,
                    label: afterEtl[i],
                    ...this.judgeNodeType(orgData, 'after-' + (i + 1), true),
                    labelCfg: {
                        position: 'bottom',
                    },
                });
                edges.push({
                    source: lastNodeId,
                    target: 'after-' + (i + 1),
                    style: {
                        stroke: '#1890ff',
                    },
                    ...this.judgeEdgeType(orgData, lastNodeId, 'after-' + (i + 1), false),
                });
                edges.push({
                    source: 'after-' + (i + 1),
                    target: 'after-end',
                    style: {
                        stroke: '#1890ff',
                    },
                    ...this.judgeEdgeType(orgData, 'after-' + (i + 1), 'after-end', true),
                });
            }
        }
        if (afterEtl.length !== 0) {
            x += 150;
            lastNodeId = 'after-end';
            nodes.push({
                id: 'after-end',
                x: x,
                y: 120,
                ...this.judgeNodeType(orgData, 'after-end', false),
            });
        }
        edges.push({
            source: lastNodeId,
            target: 'entry',
            ...this.judgeEdgeType(orgData, lastNodeId, 'entry', false),
        });
        x += 150;
        lastNodeId = 'entry';
        nodes.push({
            id: 'entry',
            x: x,
            y: 120,
            label: '条目初始化',
            ...this.judgeNodeType(orgData, 'entry', false),
            labelCfg: {
                position: 'bottom',
            },
        });
        x += 150;
        nodes.push({
            id: 'end',
            x: x,
            y: 120,
            label: '结束',
            ...this.judgeNodeType(orgData, 'end', false),
            labelCfg: {
                position: 'bottom',
            },
        });
        edges.push({
            source: lastNodeId,
            target: 'end',
            ...this.judgeEdgeType(orgData, lastNodeId, 'end', false),
        });
        // 读取数据
        this.renderG6.data({
            // 点集
            nodes: nodes,
            // 边集
            edges: edges,
        });
        // 渲染图
        this.renderG6.render();
    }
    /**
     * 判断节点类型
     */
    judgeNodeType(orgData, nodeId, isdynamic) {
        // ETL之前是否为跳过状态
        let skipBeforEtl =
            orgData.instructionInitDataState.jumpOverETL === null || orgData.instructionInitDataState.jumpOverETL === undefined
                ? false
                : orgData.instructionInitDataState.jumpOverETL;
        // etl之前
        let tatalBefore = orgData.instructionInitDataState.beforeEtlInits;
        let beforEtl = orgData.instructionInitDataState.beforeEtlInitFinishs;
        let errorBeforEtl = orgData.instructionInitDataState.beforeEtlInitErrors;
        // etl之中
        let tatalTogether = orgData.instructionInitDataState.togetherEtlInits;
        let togetherEtl = orgData.instructionInitDataState.togetherEtlInitFinishs;
        let errorTogetherEtl = orgData.instructionInitDataState.togetherEtlInitErrors;
        // etl之后
        let tatalAfter = orgData.instructionInitDataState.afterEtlInits;
        let afterEtl = orgData.instructionInitDataState.afterEtlInitFinishs;
        let errorAfterEtl = orgData.instructionInitDataState.afterEtlInitErrors;
        // etl状态
        let etlState = orgData.instructionInitDataState.instrctionInitDataStateType;
        // 初始化总状态
        let entryState = (orgData.instructionEntryInitState || {}).entryInitStateType;
        if (orgData.calculateEngineStateType === 'INITIALIZED') {
            let split = (nodeId || '').split('-') || '';
            if (isdynamic && split[0] === 'before' && skipBeforEtl) {
                return SKIP_NODE;
            } else {
                return SUCCESS_EDGE;
            }
        }
        if (isdynamic) {
            let split = nodeId.split('-');
            if (split[0] === 'before') {
                if (beforEtl.includes(tatalBefore[Number(split[1]) - 1])) {
                    if (skipBeforEtl) {
                        return SKIP_NODE;
                    } else {
                        return SUCCESS_NODE;
                    }
                } else if (errorBeforEtl.includes(tatalBefore[Number(split[1]) - 1])) {
                    return ERROR_NODE;
                } else {
                    return SYNC_NODE;
                }
            } else if (split[0] === 'together') {
                if (etlState === 'BEFOR_ETL') {
                    return INFO_NODE;
                } else if (togetherEtl.includes(tatalTogether[Number(split[1]) - 1])) {
                    return SUCCESS_NODE;
                } else if (tatalBefore.length !== beforEtl.length) {
                    return INFO_NODE;
                } else if (errorTogetherEtl.includes(tatalTogether[Number(split[1]) - 1])) {
                    return ERROR_NODE;
                } else {
                    return SYNC_NODE;
                }
            } else if (split[0] === 'after') {
                if (['BEFOR_ETL', 'TOGETHER_ETL'].includes(etlState)) {
                    return INFO_NODE;
                } else if (afterEtl.includes(tatalAfter[Number(split[1]) - 1])) {
                    return SUCCESS_NODE;
                } else if (tatalTogether.length !== togetherEtl.length) {
                    return INFO_NODE;
                } else if (errorAfterEtl.includes(tatalAfter[Number(split[1]) - 1])) {
                    return ERROR_NODE;
                } else {
                    return SYNC_NODE;
                }
            }
        } else {
            if (nodeId === 'start') {
                return SUCCESS_NODE;
            } else if (nodeId === 'start-after') {
                return SUCCESS_NODE;
            } else if (nodeId === 'before-end') {
                if (etlState === 'UNINIT' && tatalBefore.length === beforEtl.length) {
                    return SUCCESS_NODE;
                } else if (etlState === 'BEFOR_ETL') {
                    return INFO_NODE;
                } else if (etlState === 'TOGETHER_ETL') {
                    return SUCCESS_NODE;
                } else if (etlState === 'AFTER_ETL') {
                    return SUCCESS_NODE;
                } else if (etlState === 'INIT_FINISH') {
                    return SUCCESS_NODE;
                } else {
                    return INFO_NODE;
                }
            } else if (nodeId === 'together-end') {
                if (etlState === 'UNINIT' && tatalTogether.length === togetherEtl.length) {
                    return SUCCESS_NODE;
                } else if (etlState === 'BEFOR_ETL') {
                    return INFO_NODE;
                } else if (etlState === 'TOGETHER_ETL') {
                    return INFO_NODE;
                } else if (etlState === 'AFTER_ETL') {
                    return SUCCESS_NODE;
                } else if (etlState === 'INIT_FINISH') {
                    return SUCCESS_NODE;
                } else {
                    return INFO_NODE;
                }
            } else if (nodeId === 'after-end') {
                if (etlState === 'UNINIT') {
                    return INFO_NODE;
                } else if (etlState === 'BEFOR_ETL') {
                    return INFO_NODE;
                } else if (etlState === 'TOGETHER_ETL') {
                    return INFO_NODE;
                } else if (etlState === 'AFTER_ETL') {
                    return INFO_NODE;
                } else if (etlState === 'INIT_FINISH') {
                    return SUCCESS_NODE;
                } else {
                    return INFO_NODE;
                }
            } else if (nodeId === 'entry') {
                if (entryState === 'UNINITIALIZED') {
                    return INFO_NODE;
                } else if (entryState === 'INIT_ENTRY' || orgData.calculateEngineStateType === 'INIT_ENTRY') {
                    return SYNC_NODE;
                } else if (entryState === 'INITIALIZED') {
                    return SUCCESS_NODE;
                } else {
                    return INFO_NODE;
                }
            } else if (nodeId === 'end') {
                return INFO_NODE;
            } else {
                return INFO_NODE;
            }
        }
        return INFO_NODE;
    }
    /**
     * 判断连线类型
     */
    judgeEdgeType(orgData, sourceId, targetId, isdynamic) {
        if (orgData.calculateEngineStateType === 'INITIALIZED') {
            return SUCCESS_EDGE;
        }
        // etl之前
        let tatalBefore = orgData.instructionInitDataState.beforeEtlInits;
        let beforEtl = orgData.instructionInitDataState.beforeEtlInitFinishs;
        let errorBeforEtl = orgData.instructionInitDataState.beforeEtlInitErrors;
        // etl之中
        let tatalTogether = orgData.instructionInitDataState.togetherEtlInits;
        let togetherEtl = orgData.instructionInitDataState.togetherEtlInitFinishs;
        let errorTogetherEtl = orgData.instructionInitDataState.togetherEtlInitErrors;
        // etl之后
        let tatalAfter = orgData.instructionInitDataState.afterEtlInits;
        let afterEtl = orgData.instructionInitDataState.afterEtlInitFinishs;
        let errorAfterEtl = orgData.instructionInitDataState.afterEtlInitErrors;
        // etl状态
        let etlState = orgData.instructionInitDataState.instrctionInitDataStateType;
        // 条目状态
        let entryState = (orgData.instructionEntryInitState || {}).entryInitStateType;

        if (isdynamic) {
            let split = sourceId.split('-');
            if (split[0] === 'before') {
                if (beforEtl.includes(tatalBefore[Number(split[1]) - 1])) {
                    return SUCCESS_EDGE;
                } else if (errorBeforEtl.includes(tatalBefore[Number(split[1]) - 1])) {
                    return ERROR_EDGE;
                } else {
                    return SYNC_EDGE;
                }
            } else if (split[0] === 'together') {
                if (etlState === 'BEFOR_ETL') {
                    return INFO_EDGE;
                } else if (togetherEtl.includes(tatalTogether[Number(split[1]) - 1])) {
                    return SUCCESS_EDGE;
                } else if (tatalBefore.length !== beforEtl.length) {
                    return INFO_EDGE;
                } else if (errorTogetherEtl.includes(tatalTogether[Number(split[1]) - 1])) {
                    return ERROR_EDGE;
                } else {
                    return SYNC_EDGE;
                }
            } else if (split[0] === 'after') {
                if (['BEFOR_ETL', 'TOGETHER_ETL'].includes(etlState)) {
                    return INFO_EDGE;
                } else if (afterEtl.includes(tatalAfter[Number(split[1]) - 1])) {
                    return SUCCESS_EDGE;
                } else if (tatalTogether.length !== togetherEtl.length) {
                    return INFO_EDGE;
                } else if (errorAfterEtl.includes(tatalAfter[Number(split[1]) - 1])) {
                    return ERROR_EDGE;
                } else {
                    return SYNC_EDGE;
                }
            }
            return INFO_EDGE;
        } else {
            if (sourceId === 'start') {
                return SUCCESS_EDGE;
            } else if (sourceId === 'start-after') {
                return SUCCESS_EDGE;
            } else if (sourceId === 'before-end') {
                if (etlState === 'UNINIT' && tatalBefore.length === beforEtl.length) {
                    return SUCCESS_EDGE;
                } else if (etlState === 'BEFOR_ETL') {
                    return INFO_EDGE;
                } else if (etlState === 'TOGETHER_ETL') {
                    return SUCCESS_EDGE;
                } else if (etlState === 'AFTER_ETL') {
                    return SUCCESS_EDGE;
                } else if (etlState === 'INIT_FINISH') {
                    if (targetId === 'entry') {
                        if (orgData.calculateEngineStateType === 'INIT_DATA') {
                            return SYNC_EDGE;
                        } else {
                            return SUCCESS_EDGE;
                        }
                    } else {
                        return SUCCESS_EDGE;
                    }
                } else {
                    return INFO_EDGE;
                }
            } else if (sourceId === 'together-end') {
                if (etlState === 'UNINIT' && tatalTogether.length === togetherEtl.length) {
                    return SUCCESS_EDGE;
                } else if (etlState === 'BEFOR_ETL') {
                    return INFO_EDGE;
                } else if (etlState === 'TOGETHER_ETL') {
                    return INFO_EDGE;
                } else if (etlState === 'AFTER_ETL') {
                    return SUCCESS_EDGE;
                } else if (etlState === 'INIT_FINISH') {
                    if (targetId === 'entry') {
                        if (orgData.calculateEngineStateType === 'INIT_DATA') {
                            return SYNC_EDGE;
                        } else {
                            return SUCCESS_EDGE;
                        }
                    } else {
                        return SUCCESS_EDGE;
                    }
                } else {
                    return INFO_EDGE;
                }
            } else if (sourceId === 'after-end') {
                if (etlState === 'UNINIT') {
                    return INFO_EDGE;
                } else if (etlState === 'BEFOR_ETL') {
                    return INFO_EDGE;
                } else if (etlState === 'TOGETHER_ETL') {
                    return INFO_EDGE;
                } else if (etlState === 'AFTER_ETL') {
                    return INFO_EDGE;
                } else if (etlState === 'INIT_FINISH') {
                    if (targetId === 'entry') {
                        if (orgData.calculateEngineStateType === 'INIT_DATA') {
                            return SYNC_EDGE;
                        } else {
                            return SUCCESS_EDGE;
                        }
                    } else {
                        return SUCCESS_EDGE;
                    }
                } else {
                    return INFO_EDGE;
                }
            } else if (sourceId === 'entry') {
                if (entryState === 'UNINITIALIZED') {
                    return INFO_EDGE;
                } else if (entryState === 'INIT_ENTRY' || orgData.calculateEngineStateType === 'INIT_ENTRY') {
                    return SYNC_EDGE;
                } else if (entryState === 'INITIALIZED') {
                    return SUCCESS_EDGE;
                } else {
                    return INFO_EDGE;
                }
            } else {
                return INFO_EDGE;
            }
        }
    }
    /**
     * 转换数据格式 针对为undinefund的情况
     */
    changeDataFormat(data) {
        let orgData = JSON.parse(JSON.stringify(data));
        if (!data) {
            orgData = {};
        }
        if (!orgData.calculateEngineStateType) {
            orgData.calculateEngineStateType = 'UNINITIALIZED';
        }
        if (!orgData.instructionInitDataState) {
            orgData.instructionInitDataState = {};
        }

        for (let value of [
            'beforeEtlInits',
            'beforeEtlInitFinishs',
            'togetherEtlInits',
            'togetherEtlInitFinishs',
            'afterEtlInits',
            'afterEtlInitFinishs',
        ]) {
            if (!orgData.instructionInitDataState[value]) {
                orgData.instructionInitDataState[value] = [];
            }
        }
        return orgData;
    }

    /**
     * 获取下方的数据
     */
    async initFootData(type, data) {
        // 切换结果类型时重置
        this.reset();
        if (type === 'entryInit') {
            data = data || this.processData;
            let instructionEntryInitState = data.instructionEntryInitState || {};
            let successInitEntryCodes = instructionEntryInitState.successInitEntryCodes || [];
            let errorInitEntryCodes = instructionEntryInitState.errorInitEntryCodes || [];
            let filterInitEntryCodes = instructionEntryInitState.filterInitEntryCodes || [];

            this.successInitEntryCodes = successInitEntryCodes;
            this.errorInitEntryCodes = errorInitEntryCodes;
            this.filterInitEntryCodes = filterInitEntryCodes;

            const entryItems = await this.getEntry(successInitEntryCodes.concat(errorInitEntryCodes));
            this.successItemsList = successInitEntryCodes.map(key => {
                return { code: key, name: entryItems[key] };
            });
            this.errorItemsList = errorInitEntryCodes.map(key => {
                return { code: key, name: entryItems[key] };
            });

            this.pageChange(this.successFilterList, 'success');
            this.pageChange(this.errorFilterList, 'error');
        } else if (type === 'entrySync') {
            this.handleSyncDataList('1', '1', true);
            // this.footLoading = true;
        } else if (type === 'dynamicSync') {
            this.handleSyncDataList('0', '1', true);
        }
    }

    getEntry(codes) {
        return new Promise((resolve, reject) => {
            this.$axios
                .post('/synchronize/initEntry', codes)
                .then((res: any) => {
                    resolve(res);
                })
                .catch(err => reject(err));
        });
    }

    getBatchId(syncCategory) {
        return new Promise((resolve, reject) => {
            this.$axios
                .post('/synchronize/syncData', { syncCategory: syncCategory })
                .then((res: any) => {
                    console.log(this.batchId, '---------------');
                    this.amount.successAmount = res.successAmount || 0;
                    this.amount.errorAmount = res.errorAmount || 0;
                    resolve(res.batchId || '');
                })
                .catch(err => {
                    reject(err);
                });
        });
    }

    // 切换重置
    reset() {
        this.filterList = [];
        this.errorFilterList1 = [];
        this.pagingSuccess = {
            total: 0,
            currentPage: 1,
            pageSize: 10,
        };

        this.pagingError = {
            total: 0,
            currentPage: 1,
            pageSize: 10,
        };
        this.amount.successAmount = 0;
        this.amount.errorAmount = 0;
        this.$set(this.successMsg.returnData, 'list', []);
        this.$set(this.errorMsg.returnData, 'list', []);
        // 重新渲染表格的筛选条件内容
        this.tableKey++;
    }

    // 引擎同步明细(类型: 1 条目同步 0 动态维度同步,同步状态:0 失败  1 成功,,needError:是否查询错误,batchIdT:错误数据直接从成功数据的batchId))
    async handleSyncDataList(syncCategory: any, syncStatus: any, needError?: boolean, batchIdT?: string) {
        const batchId: any = batchIdT || (await this.getBatchId(syncCategory));
        this.batchId = batchId;
        needError && this.handleSyncDataList(syncCategory, '0', false, this.batchId);
        const { code, name } = this.getFilterCodeAndName(syncStatus == '0' ? this.errorFilterList1 : this.filterList);
        getSyncDataDetailItem({
            batchId,
            code,
            codeAndName: this.footData.search,
            name,
            paging: syncStatus == '0' ? this.pagingError : this.pagingSuccess,
            syncCategory,
            syncStatus,
        })
            .then((res: any) => {
                if (syncStatus == '0') {
                    this.errorInitEntryCodes = res.list || [];
                    this.pagingError.total = res.total;
                    this.$set(this.errorMsg.returnData, 'list', this.errorInitEntryCodes);
                } else {
                    this.successInitEntryCodes = res.list || [];
                    this.pagingSuccess.total = res.total;
                    this.$set(this.successMsg.returnData, 'list', this.successInitEntryCodes);
                }
                // this.footLoading = false;
            })
            .catch(() => {
                if (syncStatus == '0') {
                    this.errorInitEntryCodes = [];
                    this.pagingError.total = 0;
                    this.$set(this.errorMsg.returnData, 'list', []);
                } else {
                    this.successInitEntryCodes = [];
                    this.pagingSuccess.total = 0;
                    this.$set(this.successMsg.returnData, 'list', []);
                }
                // this.footLoading = false;
            });
    }

    handleShowData(data) {
        let retData = [];
        if (data) {
            let successEntry = data.split('##');
            retData = successEntry.map(item => {
                return {
                    entryCode: item.substr(0, item.indexOf('@@')),
                    entryName: item.substr(item.indexOf('@@') + 2),
                    key: item.substr(0, item.indexOf('@@')),
                };
            });
        }
        return retData;
    }

    get successFilterList() {
        console.log('xxxxxxxxxxxx');
        const { code, name } = this.getFilterCodeAndName(this.filterList);
        return this.handleFilterDetail(this.successItemsList, this.footData.search, code, name);
    }

    get errorFilterList() {
        const { code, name } = this.getFilterCodeAndName(this.errorFilterList1);
        return this.handleFilterDetail(this.errorItemsList, this.footData.search, code, name);
    }

    getFilterCodeAndName(data) {
        const code = (data.find(item => item.property == 'code') || {}).datas || '';
        const name = (data.find(item => item.property == 'name') || {}).datas || '';
        return { code: code && code[0], name: name && name[0] };
    }

    // 条目组明细筛选数据
    private handleFilterDetail(dataSource: any, param: any, code: string, name: string): any {
        if (!dataSource) {
            return dataSource;
        } else {
            return dataSource.filter(
                (item: any) =>
                    (item.code || '').toUpperCase().includes(code.toUpperCase()) &&
                    (item.name || '').toUpperCase().includes(name.toUpperCase()) &&
                    ((item.code || '').toUpperCase().includes(param.toUpperCase()) || (item.name || '').toUpperCase().includes(param.toUpperCase()))
            );
        }
    }

    // 前端分页(条目初始化)
    pageChange(data, type, needError = false) {
        if (this.footData.type == 'entryInit') {
            if (type == 'success') {
                this.pagingSuccess.total = data.length;
                const values = getCurrentPageData(data, this.pagingSuccess.currentPage, this.pagingSuccess.pageSize);
                this.$set(this.successMsg.returnData, 'list', values);
            } else {
                this.pagingError.total = data.length;
                const values = getCurrentPageData(data, this.pagingError.currentPage, this.pagingError.pageSize);
                this.$set(this.errorMsg.returnData, 'list', values);
            }
        } else if (this.footData.type == 'entrySync') {
            this.handleSyncDataList('1', type == 'success' ? '1' : '0', needError);
        } else if (this.footData.type == 'dynamicSync') {
            this.handleSyncDataList('0', type == 'success' ? '1' : '0', needError);
        }
    }

    // 查询
    searchByCodeOrName() {
        this.pagingSuccess.currentPage = 1;
        this.pagingError.currentPage = 1;
        this.pageChange(this.successFilterList, 'success', true);
        console.log(this.successFilterList, 'hhhhh');
    }
    filterList: any[] = [];
    errorFilterList1: any[] = [];
    // 试算结果表筛选
    handleFilterChange(filterList, type) {
        console.log(filterList, 'filterList');
        if (type == 'success') {
            this.filterList = filterList;
            this.pagingSuccess.currentPage = 1;
            this.pageChange(this.successFilterList, 'success');
        } else {
            this.errorFilterList1 = filterList;
            this.pagingError.currentPage = 1;
            this.pageChange(this.errorFilterList, 'error');
        }
    }

    /**
     * 关闭引擎
     */
    closeEngine() {
        if (['INIT_DATA', 'INIT_ENTRY'].includes(this.processData.calculateEngineStateType)) {
            const h = this.$createElement;
            this.$msgbox({
                title: '确认关闭吗？',
                message: h('div', null, [
                    h('p', { style: 'color: red' }, '1. 可能无法再次初始化'),
                    h('p', { style: 'color: red' }, '2. 可能造成系统不稳定'),
                    h('p', { style: 'color: red' }, '3. 数据库表死锁'),
                ]),
                showCancelButton: true,
                confirmButtonText: '确定',
                cancelButtonText: '取消',
            }).then(action => {
                this.closeButtonLoading = true;
                engineStop({
                    forceStop: true,
                    messageCode: UUID12() + '-' + new Date().getTime(),
                    riskCalType: 'INSTRUCTION',
                })
                    .then(() => {
                        // this.$message({
                        //     type: 'success',
                        //     message: '关闭成功',
                        // });
                        this.searchDataEngineStatus();
                    })
                    .finally(() => {
                        this.closeButtonLoading = false;
                        this.loading = false;
                    });
            });
        } else {
            this.$confirm('确认关闭吗？', '提示', {
                confirmButtonText: '确定',
                cancelButtonText: '取消',
                type: 'warning',
            }).then(() => {
                this.closeButtonLoading = true;
                engineStop({
                    forceStop: true,
                    messageCode: UUID12() + '-' + new Date().getTime(),
                    riskCalType: 'INSTRUCTION',
                })
                    .then(() => {
                        // this.$message({
                        //     type: 'success',
                        //     message: '关闭成功',
                        // });
                        this.searchDataEngineStatus();
                    })
                    .finally(() => {
                        this.closeButtonLoading = false;
                        this.loading = false;
                    });
            });
        }
    }

    /**
     * 判断是否存在错误信息
     */
    judgeExistError = process => {
        if (!process || !process.instructionInitDataState || process.calculateEngineStateType !== 'UNINITIALIZED') {
            return '';
        }
        if (process.instructionInitDataState.beforeEtlInitErrors && process.instructionInitDataState.beforeEtlInitErrors.length > 0) {
            return '初始化失败：' + process.instructionInitDataState.beforeEtlInitErrors.join(',');
        } else if (process.instructionInitDataState.togetherEtlInitErrors && process.instructionInitDataState.togetherEtlInitErrors.length > 0) {
            return '初始化失败：' + process.instructionInitDataState.togetherEtlInitErrors.join(',');
        } else if (process.instructionInitDataState.afterEtlInitErrors && process.instructionInitDataState.afterEtlInitErrors.length > 0) {
            return '初始化失败：' + process.instructionInitDataState.afterEtlInitErrors.join(',');
        } else {
            return '';
        }
    };
}
</script>

<style lang="scss" scoped>
.engine {
    padding: 10px;
    height: 100%;
    min-width: 1200px;
    .engine-hd {
        border: 2px solid #cacaca;
        padding: 10px;

        & /deep/ {
            .el-radio__input.is-disabled .el-radio__inner,
            .el-radio__input.is-disabled.is-checked .el-radio__inner {
                border-color: var(--primary);
                background: #fff;
            }

            .el-radio__input.is-disabled.is-checked .el-radio__inner::after {
                background: var(--primary);
            }
        }
    }

    .engine-time {
        border: 1px solid #cacaca;
        margin-top: 10px;
        padding: 10px;
        line-height: 2;
    }

    .engine-diagram {
        position: relative;
        overflow: auto;

        .engine-diagram-icon {
            position: absolute;
            top: 0;
            left: 0;
            width: 1400px;

            .engine-diagram-icon-wrap {
                display: flex;
                justify-content: space-between;
                flex-wrap: wrap;
                width: 190px;
                padding: 10px;

                > span {
                    margin-bottom: 5px;
                    width: 80px;
                }

                img {
                    width: 20px;
                    height: 20px;
                    vertical-align: middle;
                    margin-right: 3px;
                }
            }
        }

        .engine-diagram-box {
            min-width: 1406px;
            border: 1px solid #cacaca;
        }
    }

    .engine-result {
        margin-top: 10px;
        border: 1px solid #cacaca;
        padding: 10px;
        height: calc(100% - 428px);

        .engine-result-hd {
            padding-bottom: 10px;
            border-bottom: 1px solid #cacaca;
        }

        .engine-result-body {
            overflow: auto;
            // height: 160px;
            p {
                display: inline-block;
                margin-top: 10px;
                &:nth-child(n + 2) {
                    margin-left: 20px;
                }
            }
        }
        .engine-result-content {
            display: flex;
            min-height: 240px;
            height: calc(100% - 70px);
        }
        .border {
            border: 1px solid #cacaca;
            height: 100%;
            width: 50%;
            &:first-child {
                margin-right: 5px;
            }
        }
    }
}
</style>
